/*
* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* openUBMC is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*         http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/

#include <gtest/gtest.h>
#include <test_utilities/test_base.h>
#include "interface/network_adapter.h"
#include <ncsi_over_mctp/ncsi_over_mctp_mellanox.h>
#include <mctp/mctp.h>
#include <mc/engine.h>
#include <mc/common.h>
#include <mc/variant.h>
#include <ncsi/ncsi_protocol.h>
#include <ncsi/ncsi_socket.h>
#include "mock_ipmi_core.h"
#include <ctime>
#include <functional>
#include <vector>
#include <string>

// 声明外部 MCTP 请求处理器设置函数，具体实现在 mock_mctp.cpp 中
namespace dev {
void set_mctp_request_handler(std::function<bool(const mc::dict&, const std::vector<uint8_t>&,
                                                 std::string&)> handler);
}

namespace drivers {
namespace pcie_nic_card {
namespace mellanox {
namespace interface {
namespace test {

namespace {
// 字节序转换辅助函数
constexpr uint16_t host_to_be16(uint16_t value) {
    return static_cast<uint16_t>(((value & 0x00FFU) << 8U) | ((value & 0xFF00U) >> 8U));
}
} // namespace

class mellanox_network_adapter_test : public mc::engine::service {
public:
    mellanox_network_adapter_test(const std::string& name) : mc::engine::service(name) {}
};

// 辅助函数：清理 NetworkAdapter 的成员变量，避免析构时访问未初始化的指针
static void safe_cleanup_network_adapter(dev::NetworkAdapter* adapter) {
    if (adapter == nullptr) {
        return;
    }
    try {
        adapter->stop_ncsi_update_task();
    } catch (...) {
        // 忽略可能的异常
    }
}

// 自定义删除器：在删除前先清理资源
struct network_adapter_deleter {
    void operator()(dev::NetworkAdapter* adapter) const {
        safe_cleanup_network_adapter(adapter);
        delete adapter;
    }
};

// Mock ncsi_over_mctp_mellanox 类
class mock_ncsi_over_mctp_mellanox : public dev::ncsi_over_mctp_mellanox {
public:
    mock_ncsi_over_mctp_mellanox(dev::mctp& mctp_obj) : dev::ncsi_over_mctp_mellanox(mctp_obj) {
    }

    void set_get_version_id_result(bool result, dev::ncsi_version_id_info_t version_id = {}) {
        m_get_version_id_result = result;
        m_version_id            = version_id;
    }

    bool get_version_id(uint8_t package_id, uint8_t channel_id,
                        dev::ncsi_version_id_info_t* version_id) {
        if (version_id == nullptr) {
            return false;
        }
        if (!m_get_version_id_result) {
            return false;
        }
        *version_id = m_version_id;
        return true;
    }

private:
    bool                        m_get_version_id_result = false;
    dev::ncsi_version_id_info_t m_version_id            = {};
};

// ========================= NetworkAdapter测试 =========================
class NetworkAdapterTest : public mc::test::TestWithEngine {
protected:
    static void SetUpTestSuite() {
        TestWithEngine::SetUpTestSuite();
        // 使用与 IPMB 库期望的服务名一致的服务名，避免超时
        // IPMB 库查找的服务名是 "bmc.kepler.ipmi_core"（定义在 libraries/ipmb/ipmb.h）
        m_test_service =
            std::make_unique<mellanox_network_adapter_test>("bmc.openubmc.test_network_adapter");
        m_test_service->init();
        m_test_service->start();
        
        // 注册 mock IpmiCore 接口，避免真实的 D-Bus 调用
        m_ipmi_core_obj = test_ipmi_core_object::create();
        m_ipmi_core_obj->set_object_path("/bmc/kepler/IpmiCore");
        m_ipmi_core_obj->set_object_name("bmc.kepler.IpmiCore");
        m_test_service->register_object(m_ipmi_core_obj);
    }
    static void TearDownTestSuite() {
        try {
            if (m_ipmi_core_obj && m_test_service) {
                m_test_service->unregister_object(m_ipmi_core_obj);
                m_ipmi_core_obj.reset();
            }
            if (m_test_service) {
                m_test_service->stop();
                m_test_service.reset();
            }
            TestWithEngine::TearDownTestSuite();
        } catch (...) {
            if (m_ipmi_core_obj) {
                m_ipmi_core_obj.reset();
            }
            if (m_test_service) {
                m_test_service.reset();
            }
        }
    }
    void SetUp() override {
        static int test_counter = 0;
        test_counter++;
        std::string object_name =
            "test_network_adapter_" + std::to_string(test_counter) + "_" +
            std::to_string(std::time(nullptr));
        std::string position = std::to_string(test_counter + 5000);

        m_network_adapter = mc::make_shared<dev::NetworkAdapter>();

        // 创建 mock ncsi_over_mctp_mellanox
        m_mctp = mc::make_shared<dev::mctp>(nullptr, 0, dev::MCTP_MESSAGE_TYPE_NCSI, "");
        m_mock_ncsi = std::make_shared<mock_ncsi_over_mctp_mellanox>(*m_mctp);
    }
    void TearDown() override {
        try {
            if (m_network_adapter) {
                try {
                    m_network_adapter->stop_ncsi_update_task();
                } catch (...) {
                    // 忽略 stop_ncsi_update_task 时的异常（对象可能未初始化）
                }
                // 由于使用了 mock 接口，无需等待真实的 D-Bus 调用完成
                m_network_adapter.reset();
            }
            // 清理 MCTP 请求处理器，避免影响其他测试
            dev::set_mctp_request_handler(nullptr);
            m_mock_ncsi.reset();
            m_mctp.reset();
        } catch (...) {
            if (m_network_adapter) {
                m_network_adapter.reset();
            }
            m_mock_ncsi.reset();
            m_mctp.reset();
        }
    }

    static std::unique_ptr<mellanox_network_adapter_test> m_test_service;
    static mc::shared_ptr<test_ipmi_core_object> m_ipmi_core_obj;
    mc::shared_ptr<dev::NetworkAdapter>                  m_network_adapter;
    mc::shared_ptr<dev::mctp>                            m_mctp;
    std::shared_ptr<mock_ncsi_over_mctp_mellanox>        m_mock_ncsi;
};
std::unique_ptr<mellanox_network_adapter_test> NetworkAdapterTest::m_test_service;
mc::shared_ptr<test_ipmi_core_object> NetworkAdapterTest::m_ipmi_core_obj;

// ========================= 基本功能测试 =========================

TEST_F(NetworkAdapterTest, Constructor) {
    // Constructor 测试只验证对象能否正确创建
    // 使用自定义删除器，在析构前先清理资源，避免访问未初始化的指针
    std::unique_ptr<dev::NetworkAdapter, network_adapter_deleter> network_adapter(new dev::NetworkAdapter());
    EXPECT_TRUE(network_adapter != nullptr);
    // 对象在作用域结束时自动析构，自定义删除器会先清理资源
}

// ========================= update_firmware_version_by_ncsi 测试 =========================

TEST_F(NetworkAdapterTest, UpdateFirmwareVersionByNcsi_Success) {
    dev::ncsi_version_id_info_t version_id = {};
    version_id.firmware_ver[0]              = 1;
    version_id.firmware_ver[1]              = 2;
    version_id.firmware_ver[2]              = 0;
    version_id.firmware_ver[3]              = 0x03;
    
    // 先确保清理之前的状态
    try {
        m_network_adapter->stop_ncsi_update_task();
    } catch (...) {
        // 忽略可能的异常
    }
    // 由于使用了 mock 接口，无需等待真实的 D-Bus 调用完成
    
    // 设置 MCTP 请求处理器，模拟 GET_VERSION_ID 成功场景
    dev::set_mctp_request_handler([version_id](const mc::dict& ctx, const std::vector<uint8_t>&,
                                               std::string& rsp) {
        EXPECT_EQ(ctx.at("PacketType").as<int64_t>(), GET_VERSION_ID);
        get_version_id_rsp response{};
        response.rsp_code    = host_to_be16(COMMAND_COMPLETED);
        response.reason_code = host_to_be16(NOERROR_OR_NOREASON);
        response.firmware_ver[0] = version_id.firmware_ver[0];
        response.firmware_ver[1] = version_id.firmware_ver[1];
        response.firmware_ver[2] = version_id.firmware_ver[2];
        response.firmware_ver[3] = version_id.firmware_ver[3];
        response.pci_vid          = host_to_be16(0x0000);
        response.pci_did          = host_to_be16(0x0000);
        response.pci_ssid         = host_to_be16(0x0000);
        response.pci_svid         = host_to_be16(0x0000);
        rsp = std::string(reinterpret_cast<const char*>(&response), GET_VERSION_ID_RSP_LEN);
        return true;
    });
    
    // 需要先设置 ncsi_over_mctp_mellanox
    mc::milliseconds interval(1000);
    uint8_t          package_id = 0;
    m_network_adapter->start_ncsi_update_task_mellanox(m_mock_ncsi, interval, package_id);
    // 由于使用了 mock 接口，无需等待真实的 D-Bus 调用完成

    bool result = m_network_adapter->update_firmware_version_by_ncsi();
    EXPECT_TRUE(result);
    // 版本格式应该是 "01.02.0003"
    std::string firmware_version = m_network_adapter->FirmwareVersion.get_value().as<std::string>();
    EXPECT_TRUE(firmware_version.find("01") != std::string::npos);
    EXPECT_TRUE(firmware_version.find("02") != std::string::npos);
}

TEST_F(NetworkAdapterTest, UpdateFirmwareVersionByNcsi_GetVersionIdFailed) {
    // 设置 MCTP 请求处理器，模拟 GET_VERSION_ID 失败场景
    dev::set_mctp_request_handler([](const mc::dict&, const std::vector<uint8_t>&, std::string&) {
        return false;
    });

    mc::milliseconds interval(1000);
    uint8_t          package_id = 0;
    m_network_adapter->start_ncsi_update_task_mellanox(m_mock_ncsi, interval, package_id);
    // 由于使用了 mock 接口，无需等待真实的 D-Bus 调用完成

    bool result = m_network_adapter->update_firmware_version_by_ncsi();
    EXPECT_FALSE(result);
}

TEST_F(NetworkAdapterTest, UpdateFirmwareVersionByNcsi_DifferentVersionValues) {
    std::vector<std::tuple<uint8_t, uint8_t, uint8_t, uint8_t>> versions = {
        {0, 0, 0, 0}, {1, 2, 0, 3}, {10, 20, 0, 0xFF}, {99, 99, 0xFF, 0xFF}};

    for (auto& [v0, v1, v2, v3] : versions) {
        // 先确保清理之前的状态
        try {
            m_network_adapter->stop_ncsi_update_task();
        } catch (...) {
            // 忽略可能的异常
        }
        // 由于使用了 mock 接口，无需等待真实的 D-Bus 调用完成

        dev::ncsi_version_id_info_t version_id = {};
        version_id.firmware_ver[0]              = v0;
        version_id.firmware_ver[1]              = v1;
        version_id.firmware_ver[2]              = v2;
        version_id.firmware_ver[3]              = v3;
        // 设置 MCTP 请求处理器（在清理之后），模拟不同版本号
        dev::set_mctp_request_handler([version_id](const mc::dict& ctx, const std::vector<uint8_t>&,
                                                   std::string& rsp) {
            EXPECT_EQ(ctx.at("PacketType").as<int64_t>(), GET_VERSION_ID);
            get_version_id_rsp response{};
            response.rsp_code    = host_to_be16(COMMAND_COMPLETED);
            response.reason_code = host_to_be16(NOERROR_OR_NOREASON);
            response.firmware_ver[0] = version_id.firmware_ver[0];
            response.firmware_ver[1] = version_id.firmware_ver[1];
            response.firmware_ver[2] = version_id.firmware_ver[2];
            response.firmware_ver[3] = version_id.firmware_ver[3];
            response.pci_vid          = host_to_be16(0x0000);
            response.pci_did          = host_to_be16(0x0000);
            response.pci_ssid         = host_to_be16(0x0000);
            response.pci_svid         = host_to_be16(0x0000);
            rsp = std::string(reinterpret_cast<const char*>(&response), GET_VERSION_ID_RSP_LEN);
            return true;
        });

        mc::milliseconds interval(1000);
        uint8_t          package_id = 0;
        m_network_adapter->start_ncsi_update_task_mellanox(m_mock_ncsi, interval, package_id);
        // 由于使用了 mock 接口，无需等待真实的 D-Bus 调用完成

        bool result = m_network_adapter->update_firmware_version_by_ncsi();
        EXPECT_TRUE(result);
        m_network_adapter->stop_ncsi_update_task();
        // 由于使用了 mock 接口，无需等待真实的 D-Bus 调用完成
    }
}

TEST_F(NetworkAdapterTest, UpdateFirmwareVersionByNcsi_WithoutNcsiInitialized) {
    // 不启动任务，直接调用 update_firmware_version_by_ncsi
    bool result = m_network_adapter->update_firmware_version_by_ncsi();
    // 由于 m_ncsi_over_mctp_mellanox 为 nullptr，应该会失败
    EXPECT_FALSE(result);
}

// ========================= HandleOsResetSignal 测试 =========================

TEST_F(NetworkAdapterTest, HandleOsResetSignal_WithCallback) {
    bool callback_called = false;

    dev::os_reset_callback callback = [&callback_called]() { callback_called = true; };

    m_network_adapter->register_os_reset_callback(callback);
    m_network_adapter->HandleOsResetSignal();

    EXPECT_TRUE(callback_called);
}

TEST_F(NetworkAdapterTest, HandleOsResetSignal_WithoutCallback) {
    // 没有注册回调时应该能正常处理
    m_network_adapter->HandleOsResetSignal();
    EXPECT_TRUE(true);
}

TEST_F(NetworkAdapterTest, HandleOsResetSignal_AfterUnregister) {
    bool callback_called = false;

    dev::os_reset_callback callback = [&callback_called]() { callback_called = true; };

    m_network_adapter->register_os_reset_callback(callback);
    m_network_adapter->unregister_os_reset_callback();
    m_network_adapter->HandleOsResetSignal();

    EXPECT_FALSE(callback_called);
}

// ========================= register_os_reset_callback 测试 =========================

TEST_F(NetworkAdapterTest, RegisterOsResetCallback_Success) {
    bool callback_called = false;

    dev::os_reset_callback callback = [&callback_called]() { callback_called = true; };

    m_network_adapter->register_os_reset_callback(callback);
    m_network_adapter->HandleOsResetSignal();

    EXPECT_TRUE(callback_called);
}

TEST_F(NetworkAdapterTest, RegisterOsResetCallback_ReplaceCallback) {
    bool first_callback_called  = false;
    bool second_callback_called = false;

    dev::os_reset_callback first_callback = [&first_callback_called]() {
        first_callback_called = true;
    };
    dev::os_reset_callback second_callback = [&second_callback_called]() {
        second_callback_called = true;
    };

    m_network_adapter->register_os_reset_callback(first_callback);
    m_network_adapter->register_os_reset_callback(second_callback);
    m_network_adapter->HandleOsResetSignal();

    EXPECT_FALSE(first_callback_called);
    EXPECT_TRUE(second_callback_called);
}

// ========================= unregister_os_reset_callback 测试 =========================

TEST_F(NetworkAdapterTest, UnregisterOsResetCallback_Success) {
    bool callback_called = false;

    dev::os_reset_callback callback = [&callback_called]() { callback_called = true; };

    m_network_adapter->register_os_reset_callback(callback);
    m_network_adapter->unregister_os_reset_callback();
    m_network_adapter->HandleOsResetSignal();

    EXPECT_FALSE(callback_called);
}

TEST_F(NetworkAdapterTest, UnregisterOsResetCallback_WithoutRegister) {
    // 未注册时取消注册应该能正常处理
    m_network_adapter->unregister_os_reset_callback();
    EXPECT_TRUE(true);
}

// ========================= start_ncsi_update_task_mellanox 测试 =========================

TEST_F(NetworkAdapterTest, StartNcsiUpdateTask_Success) {
    mc::milliseconds interval(1000);
    uint8_t          package_id = 0;

    m_network_adapter->start_ncsi_update_task_mellanox(m_mock_ncsi, interval, package_id);
    // 由于使用了 mock 接口，无需等待真实的 D-Bus 调用完成

    // 验证任务已启动，可以通过停止来验证
    m_network_adapter->stop_ncsi_update_task();
    EXPECT_TRUE(true);
}

TEST_F(NetworkAdapterTest, StartNcsiUpdateTask_WithNullNcsi) {
    mc::milliseconds              interval(1000);
    uint8_t                       package_id = 0;
    dev::ncsi_over_mctp_mellanox_ptr null_ncsi = nullptr;

    // 应该能正常处理空指针
    m_network_adapter->start_ncsi_update_task_mellanox(null_ncsi, interval, package_id);
    // 由于使用了 mock 接口，无需等待真实的 D-Bus 调用完成

    m_network_adapter->stop_ncsi_update_task();
    EXPECT_TRUE(true);
}

// ========================= stop_ncsi_update_task 测试 =========================

TEST_F(NetworkAdapterTest, StopNcsiUpdateTask_WithoutStart) {
    // 未启动时停止应该能正常处理
    m_network_adapter->stop_ncsi_update_task();
    EXPECT_TRUE(true);
}

TEST_F(NetworkAdapterTest, StopNcsiUpdateTask_AfterStart) {
    mc::milliseconds interval(1000);
    uint8_t          package_id = 0;

    m_network_adapter->start_ncsi_update_task_mellanox(m_mock_ncsi, interval, package_id);
    // 由于使用了 mock 接口，无需等待真实的 D-Bus 调用完成

    m_network_adapter->stop_ncsi_update_task();
    // 由于使用了 mock 接口，无需等待真实的 D-Bus 调用完成
    EXPECT_TRUE(true);
}

// ========================= 定时器回调测试 =========================

TEST_F(NetworkAdapterTest, TimerCallback_UpdatesFirmwareVersion) {
    dev::ncsi_version_id_info_t version_id = {};
    version_id.firmware_ver[0]              = 2;
    version_id.firmware_ver[1]              = 3;
    version_id.firmware_ver[2]              = 0;
    version_id.firmware_ver[3]              = 0x04;
    m_mock_ncsi->set_get_version_id_result(true, version_id);

    mc::milliseconds interval(100);
    uint8_t          package_id = 0;
    m_network_adapter->start_ncsi_update_task_mellanox(m_mock_ncsi, interval, package_id);

    // 由于使用了 mock 接口，无需等待定时器触发
    // 验证固件版本是否被更新（由于定时器回调会调用 update_firmware_version_by_ncsi）
    // 注意：由于是异步操作，这里主要验证不会崩溃
    m_network_adapter->stop_ncsi_update_task();
    EXPECT_TRUE(true);
}

// ========================= 多实例测试 =========================

TEST_F(NetworkAdapterTest, MultiInstance) {
    std::vector<mc::shared_ptr<dev::NetworkAdapter>> network_adapters;
    for (int i = 0; i < 3; i++) {
        std::string object_name =
            "network_adapter_" + std::to_string(i) + "_" + std::to_string(std::time(nullptr)) + "_" +
            std::to_string(i * 1000);
        std::string position = std::to_string(i + 10000);

        auto network_adapter = mc::make_shared<dev::NetworkAdapter>();

        mc::milliseconds interval(1000);
        uint8_t          package_id = i;
        network_adapter->start_ncsi_update_task_mellanox(m_mock_ncsi, interval, package_id);
        network_adapters.push_back(network_adapter);
    }

    // 由于使用了 mock 接口，无需等待真实的 D-Bus 调用完成

    for (auto& network_adapter : network_adapters) {
        if (network_adapter && m_test_service) {
            try {
                network_adapter->stop_ncsi_update_task();
                // 由于使用了 mock 接口，无需等待真实的 D-Bus 调用完成
            } catch (...) {
            }
        }
    }
    network_adapters.clear();
    // 由于使用了 mock 接口，无需等待真实的 D-Bus 调用完成
    EXPECT_TRUE(true);
}

} // namespace test
} // namespace interface
} // namespace mellanox
} // namespace pcie_nic_card
} // namespace drivers


